package com.opensource.component.query.configuration;

import com.baomidou.mybatisplus.core.toolkit.Constants;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.opensource.component.query.mapper.ExtendBaseMapper;
import com.opensource.component.query.wrapper.AbstractExtendWrapper;
import org.apache.ibatis.binding.MapperMethod.ParamMap;
import org.apache.ibatis.cache.CacheKey;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;

/**
 * 分库分表插件
 *
 * @author ZonLen since on 2021/10/8 下午12:55
 */
@Intercepts(
    {
        @Signature(type = Executor.class, method = "query", args = {MappedStatement.class,
            Object.class, RowBounds.class, ResultHandler.class}),
        @Signature(type = Executor.class, method = "query", args = {MappedStatement.class,
            Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class}),
    }
)
class MybatisPlusShardingInterceptor implements Interceptor {


  @Override
  public Object intercept(Invocation invocation) throws Throwable {
    final Object[] args = invocation.getArgs();
    final MappedStatement ms = (MappedStatement) args[0];
    final String statementId = ms.getId();
    final String mapperClass = statementId.substring(0, statementId.lastIndexOf(StringPool.DOT));
    if (!ExtendBaseMapper.class.isAssignableFrom(Class.forName(mapperClass))) {
      return invocation.proceed();
    }
    if (args[1] instanceof ParamMap) {
      ParamMap<?> param = (ParamMap<?>) args[1];
      if (param.containsKey(Constants.WRAPPER)) {
        final Object o = param.get(Constants.WRAPPER);
        if (o instanceof AbstractExtendWrapper) {
          final AbstractExtendWrapper<?, ?> ew = (AbstractExtendWrapper<?, ?>) o;
          ew.doSharingJoinOperate(
              statementId.substring(statementId.lastIndexOf(StringPool.DOT) + 1));
        }
      }
    }
    return invocation.proceed();
  }

  @Override
  public Object plugin(Object target) {
    if (target instanceof Executor) {
      return Plugin.wrap(target, this);
    }
    return target;
  }

}
